package com.liruo.treasureattic.service.user.controller.impl;

import com.liruo.treasureattic.common.httpmsg.exception.CommonResultException;
import com.liruo.treasureattic.common.httpmsg.result.BaseResponse;
import com.liruo.treasureattic.common.httpmsg.result.Errno;
import com.liruo.treasureattic.common.model.constant.RedisConstant;
import com.liruo.treasureattic.common.model.constant.SessionConstant;
import com.liruo.treasureattic.common.model.dto.user.*;
import com.liruo.treasureattic.common.model.vo.user.UserVo;
import com.liruo.treasureattic.common.util.ValidatorUtil;
import com.liruo.treasureattic.config.common.util.SessionHolder;
import com.liruo.treasureattic.middleware.mail.service.MailService;
import com.liruo.treasureattic.service.user.controller.UserController;
import com.liruo.treasureattic.service.user.model.UserConstant;
import com.liruo.treasureattic.service.user.service.UserService;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@RestController
public class UserControllerImpl implements UserController {
    @Resource
    private UserService userService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private MailService mailService;
    @Resource
    private SessionRepository<Session> sessionRepository;



    @Override
    public BaseResponse<Boolean> registerPreCheck(UserRegisterPreCheckReq preCheckReq) {
        ValidatorUtil.anyNull(preCheckReq);
        String username = preCheckReq.getUsername();
        ValidatorUtil.anyNull(username);

        if (userService.existsByUn(username)) {
            throw new CommonResultException(Errno.PARAMS, "username["+username+"] exists");
        }
        return BaseResponse.success(true);
    }

    @Override
    public BaseResponse<CodeResp> limit3Code(CodeReq codeReq) {
        ValidatorUtil.anyNull(codeReq);
        ValidatorUtil.checkEmail(codeReq.getIdentity());

        String code = mailService.generateCode(codeReq.getIdentity(), UserConstant.USER_CODE_LEN);

        RBucket<String> bucket = redissonClient.getBucket(RedisConstant.USER_CODE + codeReq.getIdentity());
        //"=3"最多验证3次
        bucket.set(code + "=1" , 1, TimeUnit.MINUTES);

        return BaseResponse.success(
                new CodeResp(code,  60)
        );
    }

    @Override
    public BaseResponse<Long> registerByEmail(UserRegisterReq userRegisterReq) {
        ValidatorUtil.anyNull(userRegisterReq);
        return BaseResponse.success(userService.registerByEmail(userRegisterReq));
    }


    @Override
    public BaseResponse<UserVo> loginByEmail(HttpServletRequest request, UserLoginReq loginReq){
        ValidatorUtil.anyNull(loginReq);
        String email = loginReq.getEmail();
        ValidatorUtil.anyNull(new String[]{email}, "must has email");

        //检查有没有登录,在同一个浏览器中可能会重复登录，但是一般不会因为会自动跳转已登录页面
        Object maybeLoginUser = SessionHolder.get().getAttribute(SessionConstant.USER_LOGIN);
        if(maybeLoginUser != null){
            throw new CommonResultException(Errno.LOGIN, "用户已经登录");
        }

        //没有登录，进行登录
        UserVo userVo = userService.loginByEmail(loginReq);
        RMap<Long, String> loginStatueMap = redissonClient.getMap(RedisConstant.USER_LOGIN_Statue);
        String sessionId =  loginStatueMap.get(userVo.getId());
        if(sessionId != null){
            //挤掉之前的登录. 修改
            String newSessionId = request.changeSessionId();
            sessionRepository.deleteById(sessionId);
            loginStatueMap.put(userVo.getId(), newSessionId);
        }else{
            //保存userId=sessionId
            loginStatueMap.put(userVo.getId(), SessionHolder.get().getId());
        }
        SessionHolder.get().setAttribute(SessionConstant.USER_LOGIN, userVo);
        return BaseResponse.success(userVo);
    }

    @Override
    public BaseResponse<UserVo> getUserVo(Long id){
        ValidatorUtil.requireGreat0(id);
        return BaseResponse.success(userService.getUserVoById(id));
    }

    @PostMapping("/update")
    public BaseResponse<UserVo> updateUserById(@RequestBody UserUpdateReq userUpdateReq){
        ValidatorUtil.anyNull(userUpdateReq);
        return BaseResponse.success(userService.updateUserById(userUpdateReq, SessionHolder.getUserId()));
    }
}
